package cc.aiee.paypal.api;

import java.util.ArrayList;
import java.util.List;

import com.braintreegateway.BraintreeGateway;
import com.braintreegateway.Result;
import com.braintreegateway.Transaction;
import com.braintreegateway.Transaction.EscrowStatus;
import com.braintreegateway.Transaction.Status;
import com.braintreegateway.TransactionRequest;
import com.braintreegateway.ValidationError;
import com.braintreegateway.ValidationErrors;

import cc.aiee.core.bean.R;
import cc.aiee.core.enums.ErrCodeEnum;
import cc.aiee.core.kit.KitJson;
import cc.aiee.core.kit.KitMoney;
import cc.aiee.paypal.config.PayPalConfig;
import cc.aiee.paypal.config.PayPalConfigKit;
import cc.aiee.paypal.core.dto.PayPalRefundDTO;
import cc.aiee.paypal.core.dto.PayPalTransactionDTO;
import cc.aiee.paypal.model.PayPalRefundModel;
import cc.aiee.paypal.model.PayPalTransactionModel;
import cn.hutool.core.lang.Assert;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class PayPalApi {

	public String getToken() {
//		ClientTokenRequest clientTokenRequest = new ClientTokenRequest().customerId(aCustomerId);
//		String clientToken = gateway.clientToken().generate(clientTokenRequest);

//		 BraintreeGateway gateway = new BraintreeGateway(
//				  Environment.SANDBOX,
//				  "v8v26bkkjwwjw3ss",
//				  "qxm9gp86fyttdrwj",
//				  "26eb517c9852dbba2a8ed1cb88b60c21"
//				);
//		 return gateway.clientToken().generate();
		return getWay().clientToken().generate();

	}

	public R<PayPalTransactionDTO> create(PayPalTransactionModel transaction) {
		TransactionRequest request = new TransactionRequest();
		request.amount(KitMoney.toYUAN(transaction.getAmount()));
		request.paymentMethodNonce(transaction.getPaymentMethodNonce());
		request.deviceData(transaction.getDeviceData());
//		request.purchaseOrderNumber(transaction.getOrderNo());
		request.orderId(transaction.getOrderNo());
		request.options().submitForSettlement(true).done();

		Result<Transaction> result = getWay().transaction().sale(request);
		Transaction target = result.getTarget();

		PayPalTransactionDTO dto = new PayPalTransactionDTO();

		dto.setAmount(transaction.getAmount());// 金额
		if (target != null) {
			dto.setOrderNo(target.getOrderId()).setTranNo(target.getId());
		}

		boolean success = result.isSuccess();
		String message = result.getMessage();
		if (success) {
			Status status = target.getStatus();
			dto.setStatus(status);
			log.info("PayPal ,ok:{} ,status:{} ,msg:{}", success, status, message);
			return new R<>(ErrCodeEnum.s_success_0.getCode(), message, success, dto);
		} else {
			log.error("PayPal ,ok:{} ,status:{} ,msg:{}", success, "Fail", message);
			return new R<>(ErrCodeEnum.e_payment_603.getCode(), message, success, dto);
		}
	}

	/**
	 * 根据交易号 查询交易信息
	 * 
	 * @param transactionId 交易号
	 * @return the {@link Transaction} or raises a
	 *         {@link com.braintreegateway.exceptions.NotFoundException}.
	 * @author YangLong <br>
	 *         2020-10-15 16:20:55
	 */
	public Transaction find(String transactionId) {
		return getWay().transaction().find(transactionId);
	}

	public R<PayPalRefundDTO> cancel(PayPalRefundModel refund) {
		log.debug("PayPal Cancel,交易号:{},进行取消扣款", refund.getTranNo());
		Result<Transaction> result = getWay().transaction().voidTransaction(refund.getTranNo());
		if (!result.isSuccess()) {
			printfErrors(refund.getTranNo(), result.getErrors());
			return new R<>(ErrCodeEnum.e_cancel_601);
		}
		PayPalRefundDTO dto = new PayPalRefundDTO();
		Transaction target = result.getTarget();
		dto.setAmount(target.getAmount());
		dto.setTranNo(target.getId());
		dto.setStatus(target.getStatus());
		dto.setType(target.getType());
		return new R<>(ErrCodeEnum.s_cancel_801, result.isSuccess(), dto);
	}

	public R<PayPalRefundDTO> refund(PayPalRefundModel refund) {
		log.debug("PayPal Refund,交易号:{},退款处理", refund.getTranNo());
		Result<Transaction> result = getWay().transaction().refund(refund.getTranNo(),
				KitMoney.toYUAN(refund.getAmount()));
		if (!result.isSuccess()) {
			printfErrors(refund.getTranNo(), result.getErrors());
			return new R<>(ErrCodeEnum.e_refund_602);
		}
		PayPalRefundDTO dto = new PayPalRefundDTO();
		Transaction target = result.getTarget();
		dto.setAmount(target.getAmount());
		dto.setTranNo(target.getId());
		dto.setStatus(target.getStatus());
		dto.setType(target.getType());
		return new R<>(ErrCodeEnum.s_refund_800, result.isSuccess(), dto);
	}

	/**
	 * 是否已扣款
	 * 
	 * @param status
	 * @return
	 * @author YangLong <br>
	 *         2020-10-16 20:34:37
	 */
	public boolean hasPaid(Status status) {
		if (Status.AUTHORIZED == status || Status.SUBMITTED_FOR_SETTLEMENT == status
				|| Status.SETTLEMENT_PENDING == status) {
			return false;
		}
		return true;
	}

	/**
	 * 是否被拒绝
	 * 
	 * @param status
	 * @return true:拒绝 , false:未拒绝
	 * @author YangLong <br>
	 *         2020-10-20 15:46:00
	 */
	public boolean hasDeclined(Status status) {
		if (Status.FAILED == status || Status.PROCESSOR_DECLINED == status || Status.SETTLEMENT_DECLINED == status) {
			return true;
		}
		return false;
	}

	/**
	 * 是否已扣款
	 * 
	 * @param tranNo 交易号
	 * @return false:未扣款 , true:已扣款
	 * @author YangLong <br>
	 *         2020-10-16 20:37:31
	 */
	public boolean hasPaid(String tranNo) {
		Assert.notBlank(tranNo, "Transaction Number is Not Blank,交易号不能为空");
		Transaction find = this.find(tranNo);
		Status status = find.getStatus();
		return hasPaid(status);
	}

	/**
	 * 
	 * @param refund
	 * @return
	 * @author YangLong <br>
	 *         2020-10-15 19:42:12
	 */
	public R<PayPalRefundDTO> refundOrCancel(PayPalRefundModel refund) {
		Assert.notBlank(refund.getTranNo(), "Transaction Number is Not Blank,交易号不能为空");
		Transaction find = this.find(refund.getTranNo());

		EscrowStatus escrowStatus = find.getEscrowStatus();
		Status status = find.getStatus();

		log.info("PayPal Refund,交易号:{},退款金额:{},EscrowStatus:{},Status:{}", refund.getTranNo(), refund.getAmount(),
				escrowStatus, status);

		if (EscrowStatus.REFUNDED == escrowStatus) {
			log.warn("PayPal Refund,交易号:{} 订单已退款");
			return new R<>(ErrCodeEnum.e_refunded_600);
		}
		if (!hasPaid(status)) {
			log.warn("PayPal,交易号:{} 取消交易,忽略了退款金额,进行了全额退款!", refund.getTranNo());
			return cancel(refund);
		}
		return refund(refund);
	}

	public void printfErrors(String tranNo, ValidationErrors errors) {
		List<String> errmsg = new ArrayList<>();
		for (ValidationError error : errors.getAllDeepValidationErrors()) {
			errmsg.add(error.getMessage());
		}
		log.error("PayPal Error Msg ,交易号:{} , 错误信息:\n{}", tranNo, KitJson.toJSONString(errmsg));
	}

	public BraintreeGateway getWay(PayPalConfig payPalConfig, boolean isOpenSandbox) {
		return PayPalConfigKit.getDefault(payPalConfig, isOpenSandbox);
	}

	public BraintreeGateway getWay() {
		BraintreeGateway defaultBraintreeGateway = PayPalConfigKit.defaultBraintreeGateway;
		if (defaultBraintreeGateway == null) {
			throw new IllegalStateException("需事先初始化defaultBraintreeGateway");
		}
		return defaultBraintreeGateway;
	}
}
